﻿using System;
using System.Collections.Generic;

namespace Gman.WebApp.Models
{
    public abstract class ValidationBase : IValidationBase
    {
        protected ValidationBase()
        {
        }
        public ValidationBase(List<KeyValuePair<string, string>> validationList)
        {
            this._validationList = validationList;
        }

        protected static string DefaultRequiredMessage = "{0} es un campo requerido";

        protected static string DefaultRequiredRecipientsMessage = "{0} correct all recipient errors before saving a trigger.";

        public virtual bool CheckAndAddValidation(string name, string message)
        {
            AddValidation(name, message, this._validationList);
            return false;
        }

        private List<KeyValuePair<string, string>> _validationList = new List<KeyValuePair<string, string>>();
        public List<KeyValuePair<string, string>> ValidationList
        {
            get
            {
                return this._validationList;
            }
            protected set
            {
                _validationList = value;
            }
        }

        private static string defaultSeparator = " and ";
        public static void AddValidation(string name, string message, List<KeyValuePair<string, string>> validationList)
        {
            if (validationList.Exists(i => i.Key == name))
            {
                KeyValuePair<string, string> item = validationList.Find(i => i.Key == name);
                message = item.Value + defaultSeparator + message;
                validationList.Remove(item);
            }
            validationList.Add(KeyValue(name, message));
        }

        #region Required Field Validation
        public virtual bool RequiredFieldValidation(string name, int? val, string message)
        {
            if (!val.HasValue)
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredMessage, message));
            return true;
        }

        public virtual bool RequiredFieldValidation(string name, decimal? val, string message)
        {
            if (!val.HasValue)
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredMessage, message));
            return true;
        }

        public virtual bool RequiredFieldValidation(string name, DateTime? val, string message)
        {
            if (!val.HasValue)
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredMessage, message));
            return true;
        }

        public virtual bool RequiredFieldValidation(string name, string val, string message)
        {
            if (string.IsNullOrEmpty(val))
            {
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredMessage, message));
            }
            return true;
        }

        protected bool RequiredRecipientsValidation(string name, string val, string message)
        {
            if (string.IsNullOrEmpty(val))
            {
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredRecipientsMessage, message));
            }
            return true;
        }
        public virtual bool RequiredFieldValidation(string name, Enum val, string message)
        {
            if (val == null || val.ToString() == string.Empty || val.ToString() == "NotSet")
            {
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredMessage, message));
            }
            return true;
        }

        public virtual bool RequiredFieldValidation(string name, object val, string message)
        {
            if (val == null)
            {
                return this.CheckAndAddValidation(name, string.Format(DefaultRequiredMessage, message));
            }
            return true;
        }
        #endregion

        protected bool ValidateRange(string name, int? val, int min, int max, string message)
        {
            if (val.HasValue)
            {
                if (val.Value < min || val.Value > max)
                {
                    return this.CheckAndAddValidation(name, string.Format("{0} must be between {1} and {2}", message, min.ToString(), max.ToString()));
                }
            }
            return true;
        }

        public virtual bool ValidateRange(string name, decimal? val, decimal min, decimal max, string message)
        {
            if (val.HasValue)
            {
                if (val.Value < min || val.Value > max)
                {
                    return this.CheckAndAddValidation(name, string.Format("{0} must be between {1} and {2}", message, min.ToString(), max.ToString()));
                }
            }
            return true;
        }

        protected bool ValidatePercentRange(string name, decimal? val, decimal min, decimal max, string message)
        {
            if (val.HasValue)
            {
                if (val.Value < min || val.Value > max)
                {
                    return this.CheckAndAddValidation(name, string.Format("{0} must be between {1:p} and {2:p}", message, min, max));
                }
            }
            return true;
        }

        protected bool ValidateDateCompareLessThan(string datePropertyName, DateTime? startDate, string startDateName, DateTime? endDate, string endDateName)
        {
            // Null values should be checked by a required field check
            if (startDate.HasValue && endDate.HasValue)
            {
                if (startDate.Value >= endDate.Value)
                {
                    return this.CheckAndAddValidation(datePropertyName, string.Format("{0} must be before {1}", startDateName, endDateName));
                }
            }
            return true;
        }

        protected bool ValidateDateCompare(string datePropertyName, DateTime? startDate, string startDateName, DateTime? endDate, string endDateName)
        {
            // Null values should be checked by a required field check
            if (startDate.HasValue && endDate.HasValue)
            {
                if (startDate.Value > endDate.Value)
                {
                    return this.CheckAndAddValidation(datePropertyName, string.Format("{0} must be less than or equal to {1}", startDateName, endDateName));
                }
            }
            return true;
        }

        protected bool ValidateDecimalCompare(string decimalPropertyName, decimal? lowerValue, string lowerValueName, decimal? higherValue, string higherValueName)
        {
            // Null values should be checked by a required field check
            if (lowerValue.HasValue && higherValue.HasValue)
            {
                if (higherValue.Value < lowerValue.Value)
                {
                    return this.CheckAndAddValidation(decimalPropertyName, string.Format("{0} must be less than or equal to {1}", lowerValueName, higherValueName));
                }
            }
            return true;
        }

        public virtual bool ValidateEmailFormat(string propertyName, string value, string fieldName)
        {
            if (!ValidationBase.ValidateEmailFormat(value))
            {
                return this.CheckAndAddValidation(propertyName, string.Format("{0} must be in the format \"name@domain.com\"", fieldName));
            }

            return true;
        }

        public virtual bool ValidatePhoneNumberFormat(string propertyName, string value, string fieldName)
        {
            if (!ValidationBase.ValidatePhoneNumberFormat(value))
            {
                return this.CheckAndAddValidation(propertyName, string.Format("{0} must be in the format \"###-###-####\"", fieldName));
            }

            return true;
        }

        protected static KeyValuePair<string, string> KeyValue(string key, string value)
        {
            return new KeyValuePair<string, string>(key, value);
        }

        public virtual void HandlePropertyValidation()
        {
        }

        public static bool ValidateEmailFormat(string value)
        {
            if (!string.IsNullOrEmpty(value))
            {
                string patternOriginal = ("^([\\w-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([\\w-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");
                string patternLenient = @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
                string patternStrict = @"^(([^<>()[\]\\.,;:\s@\""]+"
                   + @"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@"
                   + @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
                   + @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
                   + @"[a-zA-Z]{2,}))$";
                return System.Text.RegularExpressions.Regex.IsMatch(value, patternStrict);
            }

            return true;
        }

        public static bool ValidatePhoneNumberFormat(string value)
        {
            if (!string.IsNullOrEmpty(value))
            {
                return System.Text.RegularExpressions.Regex.IsMatch(value, ("^[0-9]{3}\\-[0-9]{3}\\-[0-9]{4}"));
            }

            return true;
        }

        public virtual bool ValidateIntegerFormat(string propertyName, string value, string fieldName)
        {
            if (!ValidationBase.ValidateIntegerFormat(value))
            {
                return this.CheckAndAddValidation(propertyName, string.Format("{0} debe ser un entero", fieldName));
            }

            return true;
        }

        public static bool ValidateIntegerFormat(string value)
        {
            if (!string.IsNullOrEmpty(value))
            {
                return System.Text.RegularExpressions.Regex.IsMatch(value, ("^(?!^0)\\d{1,9}$"));
            }

            return true;
        }
    }
}
